/**
 * Lockbox
 * a Password and Secret Information Manager
 * View to edit and select tags
 *
 * Created by Nathan Black
 * 
 * Licensed under GPL v2
 */
 
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <UIKit/UIApplication.h>
#import <UIKit/UITable.h>
#import "LockboxTagView.h"


@interface LockboxTagView (Private)

- (void)returnFromTagView;
- (void)updateTags:(NSMutableArray*)newTags;
- (void)table:(UITable *)table insertAtRow:(int)row;
- (void)deallocTagCells;

@end


// This class is built to be subclassed by OptionsView, as it is a tag edit & select view, plus more.
@implementation LockboxTagView

- (void)dealloc
{
    [_navBar release];
    [_prefsTable release];
    [_tagsGroupCell release];
    [_addTagCell release];
    [_tagCells release];

    [super dealloc];
}

///////////// Constructor ////////////////
- (id)initWithFrame:(struct CGRect)frame app:(id)app tagDelegate:(id)tagDelegate
{
    self = [super initWithFrame:frame];
    if (self)
    {
        _transDelegate = app;
        _tagDelegate = tagDelegate;
        
        _navBar = [[UINavigationBar alloc] initWithFrame: CGRectMake(0.0f, 0.0f, frame.size.width, LBTV_NAVBAR_HEIGHT)];
        [self setNavBarButtons:FALSE];
        [_navBar setBarStyle: 3];
        [_navBar enableAnimation];
        [_navBar setDelegate: self];

        _tagsGroupCell = [[UIPreferencesTableCell alloc] init];
        [_tagsGroupCell setTitle: @"Tags"];
        
        _storage = [LockboxStorage globalInstance];
        _tagCells = [[NSMutableArray alloc] init];
        // these are variables so Options can subclass from this, and grab all the tag editing functionality easily.
        _editRowBase = 1;
        _tagGroup = 0;

        _addTagCell = [[UIPreferencesTextTableCell alloc] init];
        [_addTagCell createInsertControl];
        [_addTagCell setPlaceHolderValue:@"Add a new tag"];
        [_addTagCell setTarget:self];
        [_addTagCell setReturnAction:@selector(table:insertAtRow:)];

        frame.origin.y = LBTV_NAVBAR_HEIGHT;
        frame.size.height -= LBTV_NAVBAR_HEIGHT;
        _prefsTable = [[UIPreferencesTableEx alloc] initWithFrame: frame];
        [_prefsTable setDataSource: self];
        [_prefsTable setDelegate: self];

        [self addSubview: _navBar];
        [self addSubview: _prefsTable];
    }
    
    return self;
}

- (void)setNavBarButtons:(BOOL)editing
{
    if (editing) {
        [_navBar showLeftButton:@"Back" withStyle:2 rightButton:@"Done" withStyle:3];
    }
    else {
        [_navBar showLeftButton:@"Back" withStyle:2 rightButton:@"Edit" withStyle:0];    
    }
}

- (void)setTags:(NSMutableArray*)tags
{
    [_tagCells removeAllObjects];
    _dirty = false;
    
    // Grab the tags and alloc their cells.
    //NSLog(@"setTags: count: %d, _tagCells count: %d", [tags count], [_tagCells count]);    
    NSString* tag;
    UIPreferencesTableCell *tagCell;
    NSEnumerator* allTagEnum = [[_storage allTags] objectEnumerator];
    while ((tag = [allTagEnum nextObject])) {
        tagCell = [[[UIPreferencesTableCell alloc] init] autorelease];
        [tagCell setValue:tag];
        [_tagCells addObject:tagCell];
        
        NSString* itemTag;
        NSEnumerator* tagEnum = [tags objectEnumerator];
        while ((itemTag = [tagEnum nextObject])) {
            // Do case insensitive compares for tags
            if ([itemTag caseInsensitiveCompare:[tagCell value]] == NSOrderedSame) {
                [tagCell setChecked:TRUE];
                [tags removeObject:itemTag];
                break;
            }
        }
        
    }
    
    // grab any leftover tags (ie tags that were added in a previous view, but not yet saved)
    NSString* itemTag;
    NSEnumerator* tagEnum = [tags objectEnumerator];
    while ((itemTag = [tagEnum nextObject])) {
        tagCell = [[[UIPreferencesTableCell alloc] init] autorelease];
        [tagCell setValue:itemTag];
        [tagCell setChecked:TRUE];
        [_tagCells addObject:tagCell];        
    }
    
    NSLog(@"setTags, now reloading data _tagCells count: %d", [_tagCells count]);
    [_prefsTable reloadData];    
}

- (NSMutableArray*)saveTags
{
    NSMutableArray* newTags = [[[NSMutableArray alloc] init] autorelease];

    UIPreferencesTableCell *tagCell;
    NSEnumerator* enumerator = [_tagCells objectEnumerator];
    while ((tagCell = [enumerator nextObject])) {
        if ([tagCell isChecked]) {
            [newTags addObject:[[[tagCell value] copy] autorelease]];
        }
    }

    return newTags;
}

- (int)getTagCount
{
    if(_tagCells != NULL)
      return [_tagCells count];
    else
      return 0;
}

- (void)exitView 
{
    if (_transDelegate != nil && [_transDelegate respondsToSelector:@selector(returnFromTagView)]) {
        [_transDelegate returnFromTagView];
        [_prefsTable stopEditing];
    }
    
    NSMutableArray* newTags = [self saveTags];
    if (_tagDelegate != nil && [_tagDelegate respondsToSelector:@selector(updateTags:)]) {
        [_tagDelegate updateTags:newTags];
    }
}

- (void)navigationBar:(UINavigationBar*)navbar buttonClicked:(int)button
{
    NSLog(@"navBar buttonClicked: %d", button);
    switch (button) 
    {
        case 1: // Back
            [self exitView];
            break;

        case 0: // right button
            if ([_prefsTable isRowDeletionEnabled]) {
                //_editing = false;
                [self setNavBarButtons:FALSE];
                [_prefsTable stopEditing];
                [_prefsTable enableRowDeletion:NO animated:YES];
                [_prefsTable reloadData];
            } 
            else {
                //_editing = true;
                [self setNavBarButtons:TRUE];
                [_prefsTable enableRowDeletion:YES animated:YES];
                [_prefsTable reloadData];
            }
            break;
    }
}

- (void)alertSheet:(UIAlertSheet *)sheet buttonClicked:(int)button
{
    [sheet dismiss];
}

- (void)tableRowSelected:(NSNotification *)notification
{
    int row = [_prefsTable selectedRow];
    NSLog(@"TagView tableRowSelected: %d", row);
    if (row >= _editRowBase && row < [_tagCells count] + _editRowBase) {
        [[_prefsTable cellAtRow:row column:0] setChecked:![[_prefsTable cellAtRow:row column:0] isChecked]];
        _dirty = true;
    }
}

- (BOOL) table:(UITable *) table canDeleteRow:(int) row 
{
    //NSLog(@"TagView canDeleteRow: %d", row);
    // these row indexes are base 1
    if (row >= _editRowBase && row < [_tagCells count] + _editRowBase) {
        return YES;
    }
    else {
        return NO;
    }
}

- (void)scrollerDidEndAnimatedScrolling:(id)table
{
    if (_recentlyAdded && [_prefsTable isRowDeletionEnabled]) {
        [_addTagCell becomeFirstResponder];
        _recentlyAdded = false;
    }
}

- (BOOL) table:(UITable *) table canInsertAtRow:(int) row 
{
    NSLog(@"TagView canInsertAtRow: %d", row);
    if (row == [_tagCells count] + _editRowBase) {
        return YES;
    }
    else {
        return NO;
    }

}

- (void) table:(UITable *) table insertAtRow:(int) row 
{
    NSString* newTag = [[_addTagCell textField] text];
    if (newTag != NULL && [newTag length] > 0) {
        UIPreferencesTableCell* tagCell = [[[UIPreferencesTableCell alloc] init] retain];
        [tagCell setValue:newTag];
        [tagCell setChecked:TRUE];
        [_tagCells addObject:tagCell];
        [_addTagCell setValue:@""];
        
        NSRange range = {row, 1};
        // We need to deselect/stop editing/take focus away from the cell being edited for the cell to move properly from the
        // reloadData and scroll routines. Odd effects were occouring otherwise.
        [_prefsTable _setEditingCell:NULL];
        [_prefsTable reloadDataForInsertionOfRows:range animated:YES];
        [_prefsTable reloadData];
        [_prefsTable scrollAndCenterTableCell:_addTagCell animated:YES];
        // calling becomeFirstResponder here doesn't work - doesn't seem to while we'ere scrolling. Set a flag, then check when we
        // get a callback when we're done scrolling in scrollerDidEndAnimatedScrolling
        _recentlyAdded = true;
        _dirty = true;
    }
} 

- (void) table:(UITable *) table deleteRow:(int) row 
{
    NSLog(@"TagView deleteRow: %d", row);
    row -= _editRowBase;
    if (row >= 0 && row < [_tagCells count]) {
        // TODO: Warn the user just once per installation what they are doing here.
        UIPreferencesTableCell* cell = [_tagCells objectAtIndex:row];
        [_storage purgeTag:[cell value]];
        [_tagCells removeObjectAtIndex:row];
        [cell release];
        
        // The table hides the keyboard if editing, and deselects, but you can't select the field again unless you
        // toggle editing. Sigh, I guess we need to hold it's hand and do it for the table.
        [_addTagCell resignFirstResponder];
        [_prefsTable setKeyboardVisible:FALSE animated:TRUE];
        [_prefsTable _setEditingCell:NULL];
        _dirty = true;
    }
    else {
        //TODO NSAssert(@"Got a delete row request out of range", false);
        NSLog(@"-= Got a delete row request out of range! =-");
    }
}

// Start of Preference required methods
- (int) numberOfGroupsInPreferencesTable: (UIPreferencesTable*)table 
{
    //NSLog(@"TagView numberOfGroupsInPreferencesTable");
    return 1;
}

- (int) preferencesTable: (UIPreferencesTable*)table numberOfRowsInGroup: (int)group 
{
    NSLog(@"TagView numberOfRowsInGroup: %d", group);
    if (group == _tagGroup) {
        return [_tagCells count] + ([_prefsTable isRowDeletionEnabled] ? 1 : 0);
    }    
    else {
        //TODO: conditionally compile asserts in and out - NSAssert(@"numberOfRowsInGroup asked for an unknown group", false);
        return 0;
    }
}

- (UIPreferencesTableCell*) preferencesTable: (UIPreferencesTable*)table cellForGroup: (int)group 
{
    //NSLog(@"TagView cellForGroup: %d", group);
    if (group == _tagGroup)
        return _tagsGroupCell;
    else
        return NULL;
}

- (UIPreferencesTableCell*) preferencesTable: (UIPreferencesTable*)table cellForRow: (int)row inGroup: (int)group 
{
    NSLog(@"TagView cellForRow: %d inGroup: %d", row, group);
    if (group == _tagGroup) {
        // _editRowBase is 1 based, this is 0 based.
        row++;
        if (row >= _editRowBase && row < [_tagCells count] + _editRowBase) {
            return [_tagCells objectAtIndex:row - _editRowBase];
        }
        else if (row == [_tagCells count] + _editRowBase) {
            return _addTagCell;
        }
    }
    else {
        // TODO NSAssert(@"numberOfRowsInGroup asked for an unknown group", false);
        return NULL;
    }
}

- (float) preferencesTable: (UIPreferencesTable*)table heightForRow: (int)row inGroup: (int)group withProposedHeight: (float)proposed 
{
    //NSLog(@"TagView heightForRow: %d group: %d withProposedHeight: %4.1f", row, group, proposed);
    if (group == _tagGroup && row == -1) return proposed * 3.5;

    return proposed;
}
// End of Preferences required modules

/*- (NSMethodSignature*)methodSignatureForSelector:(SEL)selector {
    NSLog(@"LBTagView: Requested method for selector: %@", NSStringFromSelector(selector));
    return [super methodSignatureForSelector:selector];
}

- (BOOL)respondsToSelector:(SEL)aSelector {
    NSLog(@"LBTagView: Request for selector: %@", NSStringFromSelector(aSelector));
    return [super respondsToSelector:aSelector];
}

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"LBTagView: Called from: %@", NSStringFromSelector([anInvocation selector]));
    [super forwardInvocation:anInvocation];
}*/

@end
